from typing import Callable, Iterable, TypeVar

from .inputting import NoDefault, input_generic

T = TypeVar('T')


def select_options(
    prompt: str,
    options: Iterable[T],
    default: T = NoDefault, *,
    options_str: Callable[[T], str] | Iterable[str] = str,
) -> T:
    """ Asks the user to select an option from a list of options """
    options = tuple(options)

    if callable(options_str):
        options_str = tuple(map(options_str, options))
    else:
        options_str = tuple(map(str, options_str))

    if default is not NoDefault:
        default_i = options.index(default)
    else:
        default_i = NoDefault

    print(prompt + ":")
    for i, option_str in enumerate(options_str):
        print(f"{i + 1}) {option_str}")

    def parse_func(text: str) -> int:
        selected_i = int(text)
        if not 1 <= selected_i <= len(options):
            raise ValueError(f"Expected a number 1 <= x <= {len(options)}, got {selected_i}")
        return selected_i - 1

    select_prompt = "Select by number"
    selected_i = input_generic(select_prompt, default=default_i, parse_func=parse_func)
    return options[selected_i]
